package com.ybear.ybcomponent.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;

import com.ybear.ybcomponent.R;
import com.ybear.ybcomponent.RedDotStyleBuild;
import com.ybear.ybcomponent.Utils;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * 小红点布局。包裹需要小红点的控件
 *
 * 设置小红点宽度、高度
 * @see #setRedDotSize(int)
 * 设置小红点宽度
 * @see #setRedDotWidth(int)
 * 设置小红点高度
 * @see #setRedDotHeight(int)
 * 设置小红点最小宽度、最小高度。当没有文本时自动切换成最小大小
 * @see #setRedDotMinSize(int)
 * 设置小红点最小宽度
 * @see #setRedDotMinWidth(int)
 * 设置小红点最小高度
 * @see #setRedDotMinHeight(int)
 *
 * @see #setEnableAutoMinSize(boolean)
 * 设置小红点文本内容
 * @see #setText(CharSequence)
 * @see #setText(int)
 * 设置文本字体大小
 * @see #setTextSize(float)
 * 设置文本颜色资源id
 * @see #setTextColor(int)
 * 设置小红点背景颜色资源id
 * @see #setRedDotBackgroundColor(int)
 * 设置小红点字体
 * @see #setRedDotTypeface(Typeface)
 * 设置小红点样式
 * @see #setRedDotStyleBuild(RedDotStyleBuild)
 * 设置是否启用小红点
 * @see #setEnableRedDotView(boolean)
 * 设置小红点X轴
 * @see #setRedDotTranslationX(float)
 * 设置小红点Y轴
 * @see #setRedDotTranslationY(float)
 *
 * 获取小红点文本内容
 * @see #getText()
 * 获取文本字体大小
 * @see #getTextSize()
 * 设置文本颜色资源id
 * @see #getTextColor()
 * 获取小红点背景颜色资源id
 * @see #getRedDotBackgroundColor()
 * 获取小红点样式
 * @see #getRedDotStyleBuild()
 * 获取小红点控件
 * @see #getRedDotView()
 * 获取包裹的子控件
 * @see #getChildView()
 * 获取子控件宽度
 * @see #getChildWidth()
 * 获取子控件高度
 * @see #getChildHeight()
 *
 *
 * 小红点启用状态
 * @see #isEnableRedDotView()
 */
public class RedDotLayout extends FrameLayout {
    @Retention( RetentionPolicy.CLASS )
    public @interface ShowPlace {
        int TOP = 0;
        int BOTTOM = 1;
        int LEFT = 2;
        int RIGHT = 3;
        int LEFT_TOP = 4;
        int RIGHT_TOP = 5;
        int LEFT_BOTTOM = 6;
        int RIGHT_BOTTOM = 7;
    }
    @Retention( RetentionPolicy.CLASS )
    public @interface OffsetPlace {
        int CENTER = 0;
        int IN = 1;
        int OUT = 2;
    }

    private View vChild;
    private RedDotView vRedDot;
    private RedDotStyleBuild mStyleBuild;

    private CharSequence text;
    private float textSize, offsetX, offsetY;
    @ShowPlace
    private int showPlace;
    @OffsetPlace
    private int offsetPlace;
    private int redDotWidth, redDotHeight, redDotMinWidth, redDotMinHeight;
    private int redDotExtraWidth, redDotExtraAutoWidth;
    private int mBorderSize, mShadowRadius, mShadowOffsetX, mShadowOffsetY;
    @ColorInt
    private int textColor, redDotBackgroundColor, mBorderColor, mShadowColor;
    private boolean enableRedDot, autoMinSize;
    private Typeface typeface;

    public RedDotLayout(Context context) { this(context, null); }
    public RedDotLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); }
    public RedDotLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void initTypeArray(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RedDotLayout);

        /* 小红点大小 */
        redDotWidth = typedArray.getDimensionPixelSize(
                R.styleable.RedDotLayout_redDotWidth, 46
        );
        redDotHeight = typedArray.getDimensionPixelSize(
                R.styleable.RedDotLayout_redDotHeight, 46
        );
        redDotMinWidth = typedArray.getDimensionPixelSize(
                R.styleable.RedDotLayout_redDotMinWidth, 5
        );
        redDotMinHeight = typedArray.getDimensionPixelSize(
                R.styleable.RedDotLayout_redDotMinHeight, 5
        );
        redDotExtraWidth = typedArray.getDimensionPixelSize(
                R.styleable.RedDotLayout_redDotExtraWidth, 0
        );
        autoMinSize = typedArray.getBoolean(
                R.styleable.RedDotLayout_redDotAutoMinSize, true
        );
        //小红点文本内容
        text = typedArray.getString(R.styleable.RedDotLayout_redDotText);
        //小红点文本大小
        textSize = typedArray.getDimensionPixelSize(
                R.styleable.RedDotLayout_redDotTextSize, 14
        );
        //小红点文本颜色
        textColor = typedArray.getColor(
                R.styleable.RedDotLayout_redDotTextColor,
                getResources().getColor( R.color.colorWhite )
        );
        //小红点背景颜色
        redDotBackgroundColor = typedArray.getColor(
                R.styleable.RedDotLayout_redDotBackgroundColor,
                getResources().getColor( R.color.colorRedDot )
        );
        //描边大小
        mBorderSize = typedArray.getDimensionPixelSize(
                R.styleable.RedDotLayout_redDotBorderSize, 0
        );
        //描边颜色
        mBorderColor = typedArray.getColor(
                R.styleable.RedDotLayout_redDotBorderColor, Color.WHITE
        );
        //阴影半径
        mShadowRadius = typedArray.getDimensionPixelSize(
                R.styleable.RedDotLayout_redDotShadowRadius, 0
        );
        //阴影颜色
        mShadowColor = typedArray.getColor(
                R.styleable.RedDotLayout_redDotShadowColor, 0
        );
        //阴影偏移X
        mShadowOffsetX = typedArray.getDimensionPixelSize(
                R.styleable.RedDotLayout_redDotShadowOffsetX, 0
        );
        //阴影偏移Y
        mShadowOffsetY = typedArray.getDimensionPixelSize(
                R.styleable.RedDotLayout_redDotShadowOffsetY, 0
        );
        //小红点启用状态
        enableRedDot = typedArray.getBoolean(R.styleable.RedDotLayout_redDotEnable, false);
        //显示的位置。默认：rt（右上角）
        showPlace = typedArray.getInt(R.styleable.RedDotLayout_redDotShowPlace, ShowPlace.RIGHT_TOP);
        //偏移位置，默认居中（out：朝外，in：朝内，center：居中）
        offsetPlace = typedArray.getInt(
                R.styleable.RedDotLayout_redDotOffsetPlace, OffsetPlace.IN
        );
        /* 小红点偏移XY轴，用于微调 */
        offsetX = typedArray.getDimensionPixelSize(
                R.styleable.RedDotLayout_redDotOffsetX, 0
        );
        offsetY = typedArray.getDimensionPixelSize(
                R.styleable.RedDotLayout_redDotOffsetY, 0
        );

        typedArray.recycle();
    }

    private void init(Context context, AttributeSet attrs) {
        initTypeArray(context, attrs);
        //允许显示超出的子控件
        setClipChildren( false );

        mStyleBuild = new RedDotStyleBuild()
                .setTextSize( Utils.px2Dp(getContext(), textSize) )
                .setTextColor( textColor )
                .setBackgroundResourceColor( redDotBackgroundColor );
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if( getChildCount() == 1 ) {
            //创建小红点
            vRedDot = createRedDotView( redDotWidth, redDotHeight );
            //加入小红点
            addView( vRedDot );
        }
        //获取子布局
        vChild = getChildAt( 0 );
        //设置小红点样式
        setRedDotStyleBuild( mStyleBuild );
        //处理显示位置
        doShowPlace();
    }

    /**
     * 设置小红点宽度和高度
     * @param size      大小
     * @return          {@link RedDotLayout}
     */
    public RedDotLayout setRedDotSize(int size) {
        redDotWidth = size;
        redDotHeight = size;
        return this;
    }

    /**
     * 设置小红点宽度
     * @param width     宽度
     * @return          {@link RedDotLayout}
     */
    public RedDotLayout setRedDotWidth(int width) {
        redDotWidth = width;
        return this;
    }

    /**
     * 获取小红点高度
     * @param height    高度
     * @return          {@link RedDotLayout}
     */
    public RedDotLayout setRedDotHeight(int height) {
        redDotHeight = height;
        return this;
    }

    /**
     * 设置小红点最小宽度、最小高度
     * @param size      最小大小
     * @return          {@link RedDotLayout}
     */
    public RedDotLayout setRedDotMinSize(int size) {
        redDotMinWidth = size;
        redDotMinHeight = size;
        return this;
    }

    /**
     * 设置小红点最小宽度
     * @param width     宽度
     * @return          {@link RedDotLayout}
     */
    public RedDotLayout setRedDotMinWidth(int width) {
        redDotMinWidth = width;
        return this;
    }

    /**
     * 设置小红点最小高度
     * @param height    高度
     * @return          {@link RedDotLayout}
     */
    public RedDotLayout setRedDotMinHeight(int height) {
        redDotMinHeight = height;
        return this;
    }

    /**
     * 设置是否启用当不存在文本内容时自动改变成最小大小
     * @param enable    是否启用
     * @return          {@link RedDotLayout}
     */
    public RedDotLayout setEnableAutoMinSize(boolean enable) {
        autoMinSize = enable;
        if( vRedDot != null ) vRedDot.setEnableAutoMinSize( enable );
        return this;
    }

    public RedDotLayout showPlace(@ShowPlace int showPlace) {
        this.showPlace = showPlace;
        postInvalidate();
        return this;
    }

    public RedDotLayout setRedDotOffsetPlace(@OffsetPlace int offsetPlace) {
        this.offsetPlace = offsetPlace;
        postInvalidate();
        return this;
    }

    /**
     * 设置小红点额外宽度
     * @param redDotExtraWidth  宽度
     * @return                  {@link RedDotLayout}
     */
    public RedDotLayout setRedDotExtraWidth(int redDotExtraWidth) {
        this.redDotExtraWidth = Utils.dp2Px(getContext(), redDotExtraWidth);
        return this;
    }

    /**
     * 设置小红点额外自动宽度。小红点宽度由文本长度决定，所以可以通过该方法增加额外宽度，仅内容>=1时有效
     * @param redDotExtraAutoWidth      宽度
     * @return                          {@link RedDotLayout}
     */
    public RedDotLayout setRedDotExtraAutoWidth(int redDotExtraAutoWidth) {
        this.redDotExtraAutoWidth = (int) Utils.dp2Px(getContext(), redDotExtraAutoWidth);
        return this;
    }

    /**
     * 设置小红点样式
     * @param build     样式
     * @return          {@link RedDotLayout}
     */
    public RedDotLayout setRedDotStyleBuild(@NonNull RedDotStyleBuild build) {
        post( () -> {
            Typeface typeface = build.getTypeface();
            int[] p = build.getPadding();
            int color = build.getTextColor();

            ViewGroup.LayoutParams lp = vRedDot.getLayoutParams();
            lp.width = redDotWidth;
            lp.height = redDotHeight;

            vRedDot.setTextSize( build.getTextSizeUnit(), build.getTextSize() );
            if( color != 0 ) vRedDot.setTextColor( color );
            //设置小红点背景颜色
            int bgColor = build.getBackgroundResourceColor();
            if( bgColor == 0 ) bgColor = redDotBackgroundColor;
            vRedDot.setBackgroundColor( bgColor );
            //设置字体
            if( typeface != null ) vRedDot.setTypeface( typeface );
            vRedDot.setGravity( build.getGravity() );
            if( p != null ) {
                vRedDot.setPadding(
                        vRedDot.getPaddingLeft() + p[0],
                        vRedDot.getPaddingTop() + p[1],
                        vRedDot.getPaddingRight() + p[2],
                        vRedDot.getPaddingBottom() + p[3]
                );
            }
            //描边大小
            vRedDot.setBorderSize( build.getBorderSize() );
            //描边颜色
            if( build.getBorderColor() != 0 ) vRedDot.setBorderColor( build.getBorderColor() );
            //阴影半径
            vRedDot.setShadowRadius( build.getShadowRadius() );
            //阴影颜色
            if( build.getShadowColor() != 0 ) vRedDot.setShadowColor( build.getShadowColor() );
            //阴影偏移X
            vRedDot.setShadowOffsetX( build.getShadowOffsetX() );
            //阴影偏移Y
            vRedDot.setShadowOffsetY( build.getShadowOffsetY() );
            //位置
            showPlace( build.getShowPlace() );
            //自动变小
            vRedDot.setEnableAutoMinSize( build.isEnableAutoMinSize() );
            mStyleBuild = build;
        } );
        return this;
    }

    /**
     * 获取小红点样式
     * @return  样式
     */
    public RedDotStyleBuild getRedDotStyleBuild() {
        return mStyleBuild;
    }

    /**
     * 设置小红点文本内容
     * @param text  文本内容
     * @return      {@link RedDotLayout}
     */
    public RedDotLayout setText(@NonNull CharSequence text) {
        this.text = text;
        if( vRedDot != null ) vRedDot.setText( text );
        return this;
    }

    /**
     * 设置小红点文本内容
     * @param resId     文本资源Id
     * @return          {@link RedDotLayout}
     */
    public RedDotLayout setText(@StringRes int resId) {
        this.text = getResources().getString( resId );
        return setText( text );
    }

    /**
     * 获取小红点文本内容
     * @return      文本内容
     */
    public CharSequence getText() {
        return vRedDot == null ? null : vRedDot.getText();
    }

    /**
     * 设置文本字体大小
     * @param textSize  字体大小
     * @return          {@link RedDotLayout}
     */
    public RedDotLayout setTextSize(float textSize) {
        this.textSize = textSize;
        mStyleBuild.setTextSize( textSize );
        return this;
    }

    /**
     * 获取文本字体大小
     * @return      字体大小
     */
    public float getTextSize() {
        return textSize;
    }

    /**
     * 设置文本颜色资源id
     * @param textColor     资源id
     * @return              {@link RedDotLayout}
     */
    public RedDotLayout setTextColor(@ColorInt int textColor) {
        this.textColor = textColor;
        mStyleBuild.setTextColor( textColor );
        return this;
    }

    /**
     * 设置文本颜色资源id
     * @return  资源id
     */
    public int getTextColor() {
        return textColor;
    }

    /**
     * 设置小红点背景颜色资源id
     * @param color     资源id
     * @return          {@link RedDotLayout}
     */
    public RedDotLayout setRedDotBackgroundColor(@ColorInt int color) {
        redDotBackgroundColor = color;
        mStyleBuild.setBackgroundResourceColor( color );
        return this;
    }

    /**
     * 获取小红点背景颜色资源id
     * @return          资源id
     */
    @ColorInt
    public int getRedDotBackgroundColor() {
        return redDotBackgroundColor;
    }

    /**
     * 设置小红点字体
     * @param typeface  字体
     * @return          {@link RedDotLayout}
     */
    public RedDotLayout setRedDotTypeface(Typeface typeface) {
        this.typeface = typeface;
        mStyleBuild.setTypeface( typeface );
        return this;
    }

    /**
     * 获取小红点字体
     * @return          字体
     */
    public Typeface getRedDotTypeface() {
        return typeface;
    }

    public RedDotLayout setRedDotBorderSize(int size) {
        mBorderSize = size;
        return this;
    }

    public RedDotLayout setRedDotShadowRadius(int radius) {
        mShadowRadius = radius;
        return this;
    }

    public RedDotLayout setRedDotShadowOffsetX(int offsetX) {
        mShadowOffsetX = offsetX;
        return this;
    }

    public RedDotLayout setRedDotShadowOffsetY(int offsetY) {
        mShadowOffsetY = offsetY;
        return this;
    }

    public RedDotLayout setRedDotBorderColor(@ColorInt int color) {
        mBorderColor = color;
        return this;
    }

    public RedDotLayout setRedDotShadowColor(@ColorInt int color) {
        mShadowColor = color;
        return this;
    }

    /**
     * 设置是否启用小红点
     * @param enable    是否启用
     */
    public RedDotLayout setEnableRedDotView(boolean enable) {
        enableRedDot = enable;
        if( vRedDot != null ) vRedDot.setVisibility( enable ? VISIBLE : GONE );
        return this;
    }

    /**
     * 小红点启用状态
     * @return          是否被启用
     */
    public boolean isEnableRedDotView() {
        return enableRedDot;
    }

    /**
     * 获取小红点控件
     * @return          {@link RedDotView}
     */
    @Nullable
    public RedDotView getRedDotView() {
        return vRedDot;
    }

    public RedDotLayout setRedDotOffsetX(float offsetX) {
        this.offsetX = offsetX;
        return this;
    }

    public RedDotLayout setRedDotOffsetY(float offsetY) {
        this.offsetY = offsetY;
        return this;
    }

    /**
     * 设置小红点X轴
     * @param x     X轴
     */
    public RedDotLayout setRedDotTranslationX(float x) {
        if( vRedDot != null ) vRedDot.setTranslationX( x );
        return this;
    }

    /**
     * 设置小红点Y轴
     * @param y     Y轴
     */
    public RedDotLayout setRedDotTranslationY(float y) {
        if( vRedDot != null ) vRedDot.setTranslationY( y );
        return this;
    }

    /**
     * 获取包裹的子控件
     * @return          {@link View}
     */
    public View getChildView() {
        return vChild;
    }

    /**
     * 获取子控件宽度
     * @return      宽度
     */
    public int getChildWidth() {
        return vChild == null ? 0 : vChild.getMeasuredWidth();
    }

    /**
     * 获取子控件高度
     * @return      高度
     */
    public int getChildHeight() {
        return vChild == null ? 0 : vChild.getMeasuredHeight();
    }

    /**
     * 处理显示的位置
     */
    private void doShowPlace() {
        int w = redDotWidth;
        int h = redDotHeight;
        int cw = getChildWidth();
        int ch = getChildHeight();
        float x = 0F, y = 0F;
        switch ( showPlace ) {
            case ShowPlace.TOP:             //顶部
                x = ( cw / 2F ) - ( w / 2F );
                //居中、朝外、朝内
                y = offsetPlace == 0 ? -( h / 2F ) : offsetPlace == 1 ? 0 : -h;
                break;
            case ShowPlace.BOTTOM:          //底部
                x = ( cw / 2F ) - ( w / 2F );
                y = ch - ( offsetPlace == 0 ? h / 2F : offsetPlace == 1 ? h : 0 );
                break;
            case ShowPlace.LEFT:            //左边
                x = offsetPlace == 0 ? -( w / 2F ) : offsetPlace == 1 ? 0 : -w;
                y = ( ch / 2F ) - ( h / 2F );
                break;
            case ShowPlace.RIGHT:           //右边
                x = cw - ( offsetPlace == 0 ? w / 2F : offsetPlace == 1 ? w : 0 );
                y = ( ch / 2F ) - ( h / 2F );
                break;
            case ShowPlace.LEFT_TOP:        //左上角
                x = offsetPlace == 0 ? -( w / 2F ) : offsetPlace == 1 ? 0 : -w;
                y = offsetPlace == 0 ? -( h / 2F ) : offsetPlace == 1 ? 0 : -h;
                break;
            case ShowPlace.RIGHT_TOP:       //右上角
                x = cw - ( offsetPlace == 0 ? ( w / 2F ) : offsetPlace == 1 ? w : 0 );
                y = offsetPlace == 0 ? -( h / 2F ) : offsetPlace == 1 ? 0 : -h;
                break;
            case ShowPlace.LEFT_BOTTOM:     //左下角
                x = offsetPlace == 0 ? -( w / 2F ) : offsetPlace == 1 ? 0 : -w;
                y = cw - ( offsetPlace == 0 ? ( h / 2F ) : offsetPlace == 1 ? h : 0 );
                break;
            case ShowPlace.RIGHT_BOTTOM:     //右下角
                x = cw - ( offsetPlace == 0 ? w / 2F : offsetPlace == 1 ? w : 0 );
                y = ch - ( offsetPlace == 0 ? h / 2F : offsetPlace == 1 ? h : 0 );
                break;
        }
        setRedDotTranslationX( x + offsetX );
        setRedDotTranslationY( y + offsetY );
    }

    /**
     * 创建气泡View
     */
    private RedDotView createRedDotView(int width, int height) {
        RedDotView v = new RedDotView( getContext() );
        v.setLayoutParams(new LayoutParams(width, height));

        if( redDotMinWidth != 0 ) v.setMinWidth( redDotMinWidth );
        if( redDotMinHeight != 0 ) v.setMinHeight( redDotMinHeight );
        v.setEnableAutoMinSize( autoMinSize );
        //设置是否启用小红点
        v.setVisibility( enableRedDot ? VISIBLE : GONE );
        //设置小红点额外宽度
        v.setRedDotExtraWidth( redDotExtraWidth );
        //设置小红点额外自动宽度
        v.setRedDotExtraAutoWidth( redDotExtraAutoWidth );
        //描边颜色
        v.setBorderColor( mBorderColor );
        //描边大小
        v.setBorderSize( mBorderSize );
        //阴影半径
        v.setShadowRadius( mShadowRadius );
        //阴影颜色
        v.setShadowColor( mShadowColor );
        //阴影偏移X
        v.setShadowOffsetX( mShadowOffsetX );
        //阴影偏移Y
        v.setShadowOffsetY( mShadowOffsetY );

        //设置文本内容
        if( text != null ) v.setText( text );
        return v;
    }
}